package com.sixbro.orm.jpa.entity;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.sixbro.orm.jpa.entity.base.AbstractAuditModel;
import lombok.*;

import javax.persistence.*;
import java.util.Collection;

/**
 * <p>
 *  用户实体类
 * </p>
 *
 * @author: Mr.Lu
 * @since: 2021/12/10 11:11
 */
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Entity
@Table(name = "t_user")
public class User extends AbstractAuditModel {

    @Column(nullable = false, unique = true, columnDefinition = "varchar(255) comment '用于登录的账号'")
    private String username;

    @Column(nullable = false, columnDefinition = "varchar(255) comment '数据库中存储的密码'")
    // 密码不应该在前台展示
    @JsonIgnore
    private String password;

    @Column(nullable = false, columnDefinition = "varchar(255) comment '加密使用的盐'")
    @JsonIgnore
    private String salt;

    @Column(columnDefinition = "varchar(255) comment '用户的头像,数据库中仅存储文件路径'")
    private String avatar;

    @Column(columnDefinition = "varchar(255) comment '用户的联系方式'")
    private String phone;

    @Column(columnDefinition = "varchar(255) comment '用户的邮箱'")
    private String email;

    @Column(columnDefinition = "varchar(255) comment '用户的地址'")
    private String address;

    @Enumerated(EnumType.STRING)
    @Column(columnDefinition = "varchar(255) default 'MALE' comment '用户的性别'")
    //@JsonIgnore
    private State gender;

    @Column(columnDefinition = "int(2) comment '状态，-1：逻辑删除，0：禁用，1：启用'")
    private State state;

    /**
     * 每个用户有自己的角色,多个用户可以有同一个角色
     * CascadeType见 https://www.jianshu.com/p/e8caafce5445
     */
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "role_id", referencedColumnName = "id")
    @JsonIgnore
    private Role role;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "creator")
    private Collection<UserReceivingAddress> receivingAddresses;

    /**
     * 关联部门表
     * 1、关系维护端，负责多对多关系的绑定和解除
     * 2、@JoinTable注解的name属性指定关联表的名字，joinColumns指定外键的名字，关联到关系维护端(User)
     * 3、inverseJoinColumns指定外键的名字，要关联的关系被维护端(Department)
     * 4、其实可以不使用@JoinTable注解，默认生成的关联表名称为主表表名+下划线+从表表名，
     * 即表名为user_department
     * 关联到主表的外键名：主表名+下划线+主表中的主键列名,即user_id,这里使用referencedColumnName指定
     * 关联到从表的外键名：主表中用于关联的属性名+下划线+从表的主键列名,department_id
     * 主表就是关系维护端对应的表，从表就是关系被维护端对应的表
     */
    @ManyToMany(targetEntity = Department.class, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinTable(
            name = "t_user_dept",
            joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(name = "dept_id", referencedColumnName = "id")
    )
    private Collection<Department> departments;


    @Getter
    public enum State {

        DELETED(-1, "逻辑删除"),
        DISABLED(0, "禁用"),
        NORMAL(1, "启用");

        private final Integer value;
        private final String description;

        State(Integer value, String description) {
            this.value = value;
            this.description = description;
        }

        public static State of(String genderStr) {
            for (State state : values()) {
                if (state.value.equals(genderStr)) {
                    return state;
                }
            }
            return null;
        }
    }

    @Getter
    public enum Gender {

        MALE("男"),
        FEMALE("女");

        private final String value;

        Gender(String value) {
            this.value = value;
        }

        public static Gender of(String genderStr) {
            for (Gender gender : values()) {
                if (gender.value.equals(genderStr)) {
                    return gender;
                }
            }
            return null;
        }
    }
}
